package com.example.demo.controller;

import com.example.demo.utils.ClassUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletRequest;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wangyg6 on 2018/11/30.
 */
@RestController
@RequestMapping
public class MDAController {
	static Logger log = LoggerFactory.getLogger(MDAController.class);

	/**
	 * 形如 curl -X get http://ip:port/RuleWeb/MDA/OPEN_CHAIN
	 * @param key
	 * @return
	 * @throws IOException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	@RequestMapping(value = "MDA/{key}", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
	@ResponseBody
	public Result<Object> getMdas(@PathVariable("key") String key) throws IOException, IllegalAccessException {
		List<ObjMDA> resultList = new ArrayList<ObjMDA>();
		boolean dontHave = true;
		List<String> classNames = ClassUtils.findClassName("com.example.demo", "MDA.class");
		if (classNames == null || classNames.isEmpty()) {
			return new Result<Object>(ResultCode.ERROR, "未找到MDA文件");
		}
		for (String className : classNames) {
			Class<?> consClass = null;
			try {
				consClass = Class.forName(className);
			} catch (ClassNotFoundException e) {
				log.error("Can't load class by name {} !", className, e);
				continue;
			}
			Field field;
			try {
				field = consClass.getDeclaredField(key);
				dontHave = false;
			} catch (NoSuchFieldException e) {
				continue;
			}
			field.setAccessible(true);
			Object result = field.get(null);
			field.setAccessible(false);
			ObjMDA<Object> obj = new ObjMDA<Object>(className, result.getClass().getName(), key, result);
			resultList.add(obj);
		}
		if (dontHave) {
			return new Result<Object>(ResultCode.ERROR, "未找到key[" + key + "]对应的值");
		}
		return new Result<Object>(ResultCode.SUCCESS, resultList);
	}

	@RequestMapping(value = "MDA", method = RequestMethod.PUT, produces = "application/json;charset=utf-8")
	@ResponseBody
	public Result<Object> modMda(ServletRequest request)
			throws IOException, IllegalAccessException, ClassNotFoundException, NoSuchFieldException {
	/*	String key = null;
		try {
			String param = getParam(request);
			JSONObject obj = JSONObject.fromObject(param);
			Class<?> aClass = Class.forName(obj.getString("clazz"));
			key = obj.getString("key");
			Field declaredField = aClass.getDeclaredField(key);
			Object value = obj.get("value");
			Object o = SerializeUtil
					.buildObj(declaredField.getType(), declaredField.getGenericType(), value.toString());
			setValue(declaredField, o);
		} catch (Exception e) {
			return new Result<Object>(ResultCode.ERROR, "修改mda值失败:"+e);
		}
		return getMdas(key);*/

		String param = getParam(request);
		Class<?> aClass = Class.forName("com.example.demo.controller.MDA");
		if (param.equals("1")) {
			Field field = aClass.getDeclaredField("APPLICATION_TEST");
			setValue(field, false);
			return getMdas("APPLICATION_TEST");
		}
		if (param.equals("2")) {
			Field field = aClass.getDeclaredField("SR_MIX_SWITCH");
			Map<String, String> map = new HashMap<String, String>();
			map.put("All", "Y");
			setValue(field, map);
			return getMdas("SR_MIX_SWITCH");
		}
		if (param.equals("3")) {
			Field field = aClass.getDeclaredField("CHANNEL_TYPE_CD");
			setValue(field, new Integer[] { 1, 2, 3 });
			return getMdas("CHANNEL_TYPE_CD");
		}
		if (param.equals("4")) {
			Field field = aClass.getDeclaredField("MAIN_OFFER_EXCLUDE");
			setValue(field, Arrays.asList("811", "456"));
			return getMdas("MAIN_OFFER_EXCLUDE");
		}
		if (param.equals("5")) {
			Field field = aClass.getDeclaredField("SRULE_LEVEL_0");
			setValue(field, "2");
			return getMdas("SRULE_LEVEL_0");
		}
	/*	if (param.equals("6")) {
			Field field = aClass.getDeclaredField("APPLICATION_TEST");
			setValue(field, false);
			return getMdas("APPLICATION_VERSION");
		}
		if (param.equals("7")) {
			Field field = aClass.getDeclaredField("APPLICATION_TEST");
			setValue(field, false);
			return getMdas("APPLICATION_VERSION");
		}*/
		return null;

	}

	private static void setValue(Field targetField, Object newValue)
			throws NoSuchFieldException, IllegalAccessException {
		int modBak = targetField.getModifiers();
		Field modifiersField = null;
		try {
			targetField.setAccessible(true);
			modifiersField = Field.class.getDeclaredField("modifiers");
			modifiersField.setAccessible(true);
			//去掉final修饰符
			if (Modifier.isFinal(modBak)) {
				modifiersField.setInt(targetField, (modBak - Modifier.FINAL));
			}
			targetField.set(null, newValue);
		} finally {
			if (targetField.getModifiers() != modBak && modifiersField != null) {
				try {//记得把modifier修改回来，防止下次没法用
					modifiersField.setAccessible(true);
					if (!Modifier.isFinal(targetField.getModifiers())) {
						modifiersField.setInt(targetField, modBak);
					}
				} catch (Exception e) {
					//do nothing
				}
			}
		}
	}

	private static class ObjMDA<T> implements Serializable {
		private String clazz;
		private String type;
		private String key;
		private T value;

		public ObjMDA(String clazz, String type, String key, T value) {
			this.clazz = clazz;
			this.key = key;
			this.type = type;
			this.value = value;
		}

		public String getClazz() {
			return clazz;
		}

		public void setClazz(String clazz) {
			this.clazz = clazz;
		}

		public String getKey() {
			return key;
		}

		public void setKey(String key) {
			this.key = key;
		}

		public String getType() {
			return type;
		}

		public void setType(String type) {
			this.type = type;
		}

		public T getValue() {
			return value;
		}

		public void setValue(T value) {
			this.value = value;
		}
	}

	public enum ResultCode {
		SUCCESS(0, "成功"), ERROR(-1, "失败");

		int value;
		String msg;

		ResultCode(int value, String msg) {
			this.value = value;
			this.msg = msg;
		}

		public String getMsg() {
			return msg;
		}

		public int getValue() {
			return value;
		}

	}

	private static class Result<T> implements Serializable {
		private int code;
		private String msg;
		private T data;

		Result(ResultCode resultCode, T data) {
			this.code = resultCode.getValue();
			this.msg = resultCode.getMsg();
			this.data = data;
		}

		public Result(ResultCode resultCode, String msg, T data) {
			this.code = resultCode.getValue();
			this.msg = msg;
			this.data = data;
		}

		public int getCode() {
			return code;
		}

		public void setCode(int code) {
			this.code = code;
		}

		public String getMsg() {
			return msg;
		}

		public void setMsg(String msg) {
			this.msg = msg;
		}

		public T getData() {
			return data;
		}

		public void setData(T data) {
			this.data = data;
		}
	}

	private static String getParam(ServletRequest request) {
		InputStreamReader reader = null;
		String result = null;
		try {
			reader = new InputStreamReader(request.getInputStream(), "UTF-8");
			result = FileCopyUtils.copyToString(reader);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}
}
